Skip to content

HTML5 本地存储面试题全解析

一、核心要点速览

💡 核心考点

  • localStorage: 永久存储,~5MB 容量
  • sessionStorage: 会话级存储,窗口关闭即清除
  • Cookie: 传统存储,自动携带到服务器
  • IndexedDB: 大容量结构化数据存储
  • 使用场景: 根据需求选择合适的存储方案

二、三种存储方案详细对比

1. 特性对比表

特性localStoragesessionStorageCookie
生命周期永久会话级(窗口关闭)可设置过期时间
存储大小~5MB~5MB~4KB
服务器通信不参与不参与自动携带
作用域同源窗口共享当前窗口所有窗口
API简单易用简单易用复杂
数据类型字符串字符串字符串
安全性XSS 风险XSS 风险CSRF + XSS
操作复杂度O(1)O(1)O(n)

2. 使用场景决策树

需要跨会话存储?

    ├─ 是 → 需要服务器访问?
    │   │
    │   ├─ 是 → Cookie (HttpOnly)
    │   │   └─ Token、Session ID
    │   │
    │   └─ 否 → localStorage
    │       └─ 用户偏好设置、主题配置、购物车

    └─ 否 → 临时数据?

        ├─ 是 → sessionStorage
        │   └─ 表单临时数据、一次性消息、分页状态

        └─ 否 → 大量结构化数据?

            ├─ 是 → IndexedDB
            │   └─ 离线应用、文件缓存、数据库

            └─ 否 → localStorage
                └─ 简单键值对存储

三、localStorage 详解

1. 基础 API

javascript
// 1. 存储数据
localStorage.setItem('key', 'value')

// 2. 读取数据
const value = localStorage.getItem('key')

// 3. 删除单个数据
localStorage.removeItem('key')

// 4. 清空所有数据
localStorage.clear()

// 5. 获取存储长度
const length = localStorage.length

// 6. 通过索引获取 key
const key = localStorage.key(0)

2. 存储对象和数组

javascript
// ❌ 错误:直接存储对象
const user = { name: 'Vue', age: 3 }
localStorage.setItem('user', user) 
// 结果:"[object Object]"

// ✓ 正确:使用 JSON 序列化
const user = { name: 'Vue', age: 3 }
localStorage.setItem('user', JSON.stringify(user))

// 读取时解析
const savedUser = JSON.parse(localStorage.getItem('user'))
console.log(savedUser.name) // 'Vue'

// ✓ 封装工具函数
const storage = {
  set(key, value) {
    localStorage.setItem(key, JSON.stringify(value))
  },
  get(key) {
    const value = localStorage.getItem(key)
    return value ? JSON.parse(value) : null
  },
  remove(key) {
    localStorage.removeItem(key)
  }
}

// 使用
storage.set('config', { theme: 'dark', lang: 'zh' })
const config = storage.get('config')

3. 监听存储变化

javascript
// storage 事件只在其他窗口/标签页触发
window.addEventListener('storage', (e) => {
  console.log(`
    Key: ${e.key}
    Old Value: ${e.oldValue}
    New Value: ${e.newValue}
    URL: ${e.url}
    Storage Area: ${e.storageArea}
  `)
  
  // 应用场景:多标签页同步
  if (e.key === 'theme') {
    document.body.className = e.newValue
  }
})

// 主动通知其他标签页
function notifyThemeChange(theme) {
  localStorage.setItem('theme', theme)
  // 触发 storage 事件
}

四、sessionStorage 详解

1. 与 localStorage 的区别

javascript
// sessionStorage API 与 localStorage 完全相同
sessionStorage.setItem('temp', 'data')
const data = sessionStorage.getItem('temp')
sessionStorage.removeItem('temp')

// 关键区别:生命周期
// - localStorage: 永久存储,除非手动清除
// - sessionStorage: 窗口/标签页关闭即清除

// 示例:表单草稿保存
const form = document.querySelector('#myForm')

form.addEventListener('input', () => {
  sessionStorage.setItem('formData', JSON.stringify({
    name: form.name.value,
    email: form.email.value
  }))
})

// 页面加载时恢复
window.addEventListener('load', () => {
  const saved = sessionStorage.getItem('formData')
  if (saved) {
    const data = JSON.parse(saved)
    form.name.value = data.name
    form.email.value = data.email
  }
})

// 提交后清除
form.addEventListener('submit', (e) => {
  sessionStorage.removeItem('formData')
})

2. 典型应用场景

┌──────────────────────────────────────────────────────────┐
│              sessionStorage 应用场景                      │
└──────────────────────────────────────────────────────────┘

✓ 表单临时数据
  ┌──────────────────────────────┐
  │ 用户填写表单 → 临时保存       │
  │ 提交成功 → 清除               │
  │ 关闭窗口 → 自动清除           │
  └──────────────────────────────┘

✓ 分页状态
  ┌──────────────────────────────┐
  │ 列表页 → 保存当前页码         │
  │ 进入详情 → 返回列表保持状态   │
  │ 关闭窗口 → 状态清除           │
  └──────────────────────────────┘

✓ 一次性消息
  ┌──────────────────────────────┐
  │ Toast 提示 → 存储显示状态     │
  │ 显示后 → 立即清除             │
  └──────────────────────────────┘

✗ 不适合的场景:
  - 用户偏好设置(应用 localStorage)
  - 登录 token(应用 Cookie)
  - 长期缓存数据
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

五、Cookie 详解

javascript
// 1. 设置 Cookie(不推荐手动操作,用库更好)
document.cookie = "name=value; expires=Thu, 31 Dec 2024 23:59:59 UTC; path=/; domain=.example.com; secure; HttpOnly"

// 2. 读取 Cookie
const cookies = document.cookie.split('; ').reduce((acc, cookie) => {
  const [key, value] = cookie.split('=')
  acc[key] = decodeURIComponent(value)
  return acc
}, {})

// 3. 删除 Cookie(设置过期时间为过去)
document.cookie = "name=; expires=Thu, 01 Jan 1970 00:00:00 UTC; path=/"

// ✓ 推荐使用 js-cookie 库
import Cookies from 'js-cookie'

Cookies.set('name', 'value', { 
  expires: 7,           // 7 天
  path: '/',            // 路径
  secure: true,         // 仅 HTTPS
  sameSite: 'strict'    // CSRF 防护
})

const value = Cookies.get('name')
Cookies.remove('name')
┌──────────────────────────────────────────────────────────┐
│                  Cookie 重要属性                          │
└──────────────────────────────────────────────────────────┘

Secure:
  ┌────────────────────────────────┐
  │ ✓ 仅通过 HTTPS 传输            │
  │ ✗ HTTP 请求不会携带            │
  │ 生产环境必须设置!             │
  └────────────────────────────────┘

HttpOnly:
  ┌────────────────────────────────┐
  │ ✓ JavaScript 无法访问          │
  │ ✗ 防止 XSS 窃取 Cookie          │
  │ 敏感信息必须设置!             │
  └────────────────────────────────┘

SameSite:
  ┌────────────────────────────────┐
  │ Strict: 完全禁止第三方 Cookie  │
  │ Lax: 允许部分第三方请求        │
  │ None: 允许所有(需 Secure)    │
  │ CSRF 防护的重要手段!          │
  └────────────────────────────────┘

Domain & Path:
  ┌────────────────────────────────┐
  │ Domain: 指定 Cookie 作用域      │
  │ Path: 指定 Cookie 路径          │
  │ 合理设置避免泄露!             │
  └────────────────────────────────┘

六、IndexedDB 简介

1. 基础用法

javascript
// 1. 打开数据库
const request = indexedDB.open('MyDatabase', 1)

// 2. 数据库升级(首次创建或版本号增加)
request.onupgradeneeded = (event) => {
  const db = event.target.result
  
  // 创建对象存储空间(类似表)
  const store = db.createObjectStore('users', { 
    keyPath: 'id',        // 主键
    autoIncrement: true   // 自增
  })
  
  // 创建索引
  store.createIndex('name', 'name', { unique: false })
  store.createIndex('email', 'email', { unique: true })
}

// 3. 使用数据库
request.onsuccess = (event) => {
  const db = event.target.result
  
  // 添加数据
  function addUser() {
    const tx = db.transaction('users', 'readwrite')
    const store = tx.objectStore('users')
    
    store.add({ name: 'Vue', age: 3, email: '[email protected]' })
    
    tx.oncomplete = () => console.log('添加成功')
  }
  
  // 查询数据
  function getUser(id) {
    const tx = db.transaction('users', 'readonly')
    const store = tx.objectStore('users')
    
    const request = store.get(id)
    request.onsuccess = () => {
      console.log('用户:', request.result)
    }
  }
  
  // 使用索引查询
  function getUserByName(name) {
    const tx = db.transaction('users', 'readonly')
    const store = tx.objectStore('users')
    const index = store.index('name')
    
    const request = index.get(name)
    request.onsuccess = () => {
      console.log('用户:', request.result)
    }
  }
}

request.onerror = (event) => {
  console.error('数据库错误:', event.target.error)
}

2. IndexedDB 特点

┌──────────────────────────────────────────────────────────┐
│              IndexedDB 特点                               │
└──────────────────────────────────────────────────────────┘

优势:
✓ 大容量:无硬限制,通常 > 50MB
✓ 结构化:支持对象存储和索引
✓ 事务:完整的事务支持
✓ 查询:支持索引查询和游标遍历
✓ 文件:可以存储 Blob/File 类型

劣势:
✗ 复杂:API 较为复杂
✗ 异步:所有操作都是异步的
✗ 兼容性:需要 polyfill(老浏览器)

适用场景:
✓ 离线应用的数据缓存
✓ 大量结构化数据存储
✓ 文件、图片存储
✓ 复杂的查询需求

不适用场景:
✗ 简单的键值对(用 localStorage)
✗ 小数据量(杀鸡用牛刀)
✗ 需要同步操作
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

七、存储方案性能对比

1. 容量对比

存储容量可视化:
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
Cookie:
  ┌────────────────────────────────┐
  │ ████                           │ 4KB
  │ 每个域名                        │
  │ 每次请求都发送,浪费带宽        │
  └────────────────────────────────┘

localStorage/sessionStorage:
  ┌────────────────────────────────┐
  │ ██████████████████████████████│ 5MB
  │ 每个源 (origin)                 │
  │ 不发送到服务器                 │
  └────────────────────────────────┘

IndexedDB:
  ┌────────────────────────────────┐
  │ ██████████████████████████████│ 无硬限制
  │ ██████████████████████████████│ 动态分配
  │ ██████████████████████████████│ (通常 > 50MB)
  │ 适合大数据存储                 │
  └────────────────────────────────┘

性能影响:
  Cookie 过多 → 请求变慢
  localStorage → 不影响请求
  IndexedDB → 异步操作不阻塞
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

2. 读写性能测试

javascript
// 性能对比测试
const iterations = 10000

// Cookie
console.time('Cookie')
for (let i = 0; i < iterations; i++) {
  document.cookie = `key${i}=value${i}`
}
console.timeEnd('Cookie') // ~500ms

// localStorage
console.time('localStorage')
for (let i = 0; i < iterations; i++) {
  localStorage.setItem(`key${i}`, `value${i}`)
}
console.timeEnd('localStorage') // ~50ms

// IndexedDB (异步,实际更快)
console.time('IndexedDB')
// ... 批量写入操作
console.timeEnd('IndexedDB') // ~20ms

结论:
localStorage: 比 Cookie 快约 10
IndexedDB: 大数据场景最优
Cookie: 性能最差

八、安全注意事项

1. 安全风险与防护

┌──────────────────────────────────────────────────────────┐
│              本地存储安全最佳实践                         │
└──────────────────────────────────────────────────────────┘

❌ 不要存储敏感信息:
┌────────────────────────────────┐
│ localStorage 可以被 JavaScript │
│ 访问,XSS 攻击可以轻松窃取     │
│                                │
│ ✗ 密码、token、银行卡号等      │
│   绝对不能存 localStorage!     │
└────────────────────────────────┘

✓ 使用 HttpOnly Cookie:
┌────────────────────────────────┐
│ 敏感信息应该存在 HttpOnly      │
│ Cookie 中,JavaScript 无法访问 │
│                                │
│ ✓ Token、Session ID            │
│ ✓ 用户身份标识                 │
└────────────────────────────────┘

✓ 数据验证:
┌────────────────────────────────┐
│ 从存储读取的数据要验证         │
│                                │
│ try {
│   const data = JSON.parse(
│     localStorage.getItem('x')
│   )
│   // 验证数据结构
│ } catch(e) {
│   // 处理错误
│ }
└────────────────────────────────┘

✓ CSP 策略:
┌────────────────────────────────┐
│ 设置 Content-Security-Policy   │
│ 减少 XSS 攻击风险              │
│                                │
│ Content-Security-Policy:       │
│ default-src 'self'            │
└────────────────────────────────┘

九、面试标准回答

HTML5 提供了三种主要的本地存储方案:localStorage、sessionStorage 和 IndexedDB,另外传统的 Cookie 也还在使用。

localStorage 是永久存储,容量约 5MB,数据一直保留直到手动清除。适用于用户偏好设置、主题配置等需要跨会话的数据。但它不能存储敏感信息,因为 XSS 攻击可以窃取。

sessionStorage 与 localStorage API 相同,但生命周期仅限于当前窗口或标签页,关闭即清除。适用于表单临时数据、分页状态等一次性数据。

Cookie 容量只有 4KB,会自动发送到服务器,浪费带宽。现在主要用于身份认证(配合 HttpOnly 保证安全)。

IndexedDB 是大容量结构化存储,没有硬限制,支持事务和索引查询。适用于离线应用、大量数据缓存等复杂场景。

选择策略

  • 简单键值对 → localStorage
  • 临时数据 → sessionStorage
  • 敏感信息 → HttpOnly Cookie
  • 大量结构化数据 → IndexedDB

十、记忆口诀

本地存储歌诀:

local 永久 session 暂,
Cookie 太小还费网。
五兆空间 local 好,
敏感信息 Cookie 藏。

indexDB 容量大,
结构化数据存储强。
XSS 要防范,
HttpOnly 保安全!

十一、推荐资源


十二、总结一句话

  • localStorage: 永久存储 + 大容量 = 用户偏好首选 💾
  • sessionStorage: 会话级 + 窗口隔离 = 临时数据最佳 ⏱️
  • Cookie: 小容量 + 自动携带 = 身份认证专用 🔐
  • IndexedDB: 超大容量 + 结构化 = 离线应用利器 🗄️
最近更新